Remove the deprecated RFC7523OAuthClientProvider#3169
Conversation
The provider implemented the RFC 7523 §2.1 jwt-bearer authorization grant with an SDK-minted or prebuilt JWT, which no MCP auth extension specifies, and has been deprecated since 1.23.0 in favour of ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, and IdentityAssertionOAuthProvider. Drop it and its JWTParameters model ahead of v2, with a migration entry mapping each of its modes to a replacement.
📚 Documentation preview
|
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
LGTM — a clean, deletion-only removal of an already-deprecated provider, with the migration guide mapping every mode to its replacement. The one inline comment is adjacent cleanup in oauth2.py (the now-dead token_data hook), not a defect in this PR, and can be handled here or in a follow-up.
Extended reasoning...
Overview
The PR deletes RFC7523OAuthClientProvider and JWTParameters from mcp.client.auth.extensions.client_credentials, removes their tests (including the docs test that existed only to explain why the docs page did not count the deprecated provider), and adds a migration-guide section mapping each of the provider's three modes to its purpose-built replacement. No surviving code is modified — the diff is pure deletion plus docs.
Security risks
None introduced: this is code removal in the OAuth client extensions, and the surviving providers (ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider) are untouched. I grepped the whole repo and found no remaining references to the deleted names in src/, tests/, docs/ (other than the new migration entry), or .github/actions/conformance/client.py — nothing can break at import time. The only residue is the now-dead token_data hook parameter in OAuthClientProvider._exchange_token_authorization_code (src/mcp/client/auth/oauth2.py:386-396), flagged inline; I verified it is harmless today because the or {} guard replaces the shared mutable default before any mutation.
Level of scrutiny
Although this touches the auth package, it is a deletion-only change of a class deprecated since 1.23.0 (warning on construction), which cannot alter the behavior of any remaining auth flow. The repo's branching model expects intentional breaking changes on main (the V2 rework) documented in docs/migration.md, and that requirement is met — including an explicit note that the hybrid authorization_code + private_key_jwt mode is intentionally dropped with no replacement. That design decision was effectively made when the provider was deprecated in #1663; this PR executes it.
Other factors
The remaining module keeps its tests intact (ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, SignedJWTParameters, static_assertion_provider all still covered), and the PR description reports 100% coverage and a clean strict-no-cover run. The single finding is a nit in a file the PR does not touch, so it does not block approval.
The keyword-only token_data parameter on
OAuthClientProvider._exchange_token_authorization_code existed only so
RFC7523OAuthClientProvider could inject a client assertion into the
authorization-code exchange. With that provider gone it had no callers and
carried a mutable {} default, so build the request body as a local dict
instead. Also spell the migration guide's constructor examples with keyword
arguments so they run as written.
There was a problem hiding this comment.
LGTM — the deprecated RFC7523OAuthClientProvider/JWTParameters removal is clean, and the follow-up commit that also removed the now-dead token_data hook from _exchange_token_authorization_code resolves my earlier inline comment.
What was reviewed:
- Confirmed no remaining references to the removed names in
src/ordocs/outside the migration guide;SignedJWTParameters(the survivor) is unaffected. - Verified the
oauth2.pysignature simplification is behavior-preserving — all remaining callers (the internal flow call and six tests intests/client/test_auth.py) pass only(auth_code, code_verifier), and the locally-built dict has identical contents. - Checked the migration guide's replacements exist (
ClientCredentialsOAuthProvider,PrivateKeyJWTOAuthProvider,IdentityAssertionOAuthProvider) and that both prior reviewer comments (cubic's kwargs nit, mytoken_datanit) were addressed.
Extended reasoning...
Overview
The PR removes the long-deprecated RFC7523OAuthClientProvider and its JWTParameters model from mcp.client.auth.extensions.client_credentials, deletes their tests, adds a migration-guide section mapping each of the provider's three modes to its replacement, and (in a follow-up commit responding to review feedback) removes the token_data hook parameter from OAuthClientProvider._exchange_token_authorization_code in oauth2.py — the deleted provider was that hook's sole consumer.
Security risks
The diff touches OAuth client code, but it is almost entirely deletion. The one behavioral file change, oauth2.py, replaces a mutable-default parameter plus dict.update() with a locally-built dict containing the identical keys; I verified every remaining call site (internal call at oauth2.py:314 and six tests in tests/client/test_auth.py) passes only positional (auth_code, code_verifier), so no caller breaks and no request content changes. Removing the shared-mutable-default hook is a small security improvement rather than a risk: it eliminates a latent path for form fields (auth codes, client secrets) to leak between token exchanges if the guard line were ever refactored away.
Level of scrutiny
This is a breaking removal on the v2 branch, where AGENTS.md explicitly expects intentional breaking changes documented in docs/migration.md — which this PR does, including an explicit note that the hybrid authorization_code+private_key_jwt mode is dropped without replacement and an invitation to open an issue. The removed provider warned on construction since 1.23.0, implemented a flow no MCP auth extension specifies, and was mostly # pragma: no cover. The remaining scrutiny needed is mechanical (dangling references, caller breakage), which I checked directly.
Other factors
Both prior reviewer comments were addressed by subsequent commits: cubic's migration-snippet kwargs fix and my own inline comment about the leftover token_data hook (fixed in 05dad48 exactly as suggested). The bug hunting system found no issues this run. Surviving providers (ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, SignedJWTParameters, static_assertion_provider) retain their full test coverage, and docs/client/oauth-clients.md plus its doc-tests were updated consistently (the test asserting the deprecated provider warns was removed along with the provider).
Removes
RFC7523OAuthClientProviderand itsJWTParametersmodel frommcp.client.auth.extensions.client_credentials, ahead of v2.Motivation and Context
RFC7523OAuthClientProviderimplemented the RFC 7523 §2.1jwt-bearerauthorization grant with an SDK-minted or prebuilt JWT (plus a hybridauthorization_code+private_key_jwtmode). It landed in #1247, then was deprecated five weeks later in #1663 once the client-credentials extension (SEP-1046) settled on theclient_credentialsgrant with §2.2private_key_jwtclient authentication instead — the flowPrivateKeyJWTOAuthProviderimplements. It has warned on construction since 1.23.0 (Dec 2025).No MCP auth extension specifies the flow it implements, no other SDK ships an equivalent, and nearly all of its flow methods were
# pragma: no cover. Every mode has a purpose-built replacement:ClientCredentialsOAuthProviderprivate_key_jwt(§2.2) →PrivateKeyJWTOAuthProviderwithSignedJWTParameters/static_assertion_providerjwt-bearer(SEP-990) →IdentityAssertionOAuthProviderThe one sanctioned future use of a bare §2.1 grant, SEP-1933 Workload Identity Federation, is still a draft and wants a different shape (platform-provisioned assertion, no dynamic registration or interactive base class), so it will get its own provider rather than a resurrection of this one.
How Has This Been Tested?
Removed the tests for the deleted classes; the remaining
client_credentials.pymodule stays at 100% coverage andstrict-no-coveris clean. Confirmed at the package boundary that the removed names raiseImportError, the surviving providers still construct ashttpx2.Authunder-W error, and every module in the package imports cleanly.Breaking Changes
Yes —
RFC7523OAuthClientProviderandJWTParametersare gone.docs/migration.mdmaps each mode to its replacement.Types of changes
Checklist
AI Disclaimer